[HVM] Move ACPI timer to HV, which is the last platform timer in Qemu.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Wed, 25 Oct 2006 10:50:54 +0000 (11:50 +0100)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Wed, 25 Oct 2006 10:50:54 +0000 (11:50 +0100)
We found Vista polls ACPI timer very frequently (about 15 times
averagely) when handling timer (RTC @ 64HZ) interrupt routine. Though
the exact reason is known, it should be related to system time
adjustment. When it's in Qemu, the overhead is big. After moving,
Vista's idle overhead decreases dramatically from ~10% to 0.9%.=20

Another benefit is that Vista can only pass Performance rating with
this patch. The root cause is that ACPI timer in Qemu isn't
synchronous with other platform timer in HV, which results in Vista
complains "can't measure TSC frequency".

This patch changes vpit.h to vpt.h, for it not only has pit structure
in it, but other platform timer's structure. Another change is moving
ACPI timer and related address from acpi.h to ioreq.h, which can be shared
by HV and ACPI firmware.

Signed-off-by: Xiaowei Yang <xiaowei.yang@intel.com>
13 files changed:
tools/firmware/acpi/acpi_fadt.h
xen/arch/x86/hvm/Makefile
xen/arch/x86/hvm/hvm.c
xen/arch/x86/hvm/i8254.c
xen/arch/x86/hvm/io.c
xen/arch/x86/hvm/pmtimer.c [new file with mode: 0644]
xen/arch/x86/hvm/rtc.c
xen/arch/x86/hvm/svm/svm.c
xen/arch/x86/hvm/vmx/vmx.c
xen/include/asm-x86/hvm/domain.h
xen/include/asm-x86/hvm/vpit.h [deleted file]
xen/include/asm-x86/hvm/vpt.h [new file with mode: 0644]
xen/include/public/hvm/ioreq.h

index d1ecea5588b9c8c49f06a6062d17e2b3b34103e3..f30a1dac98b34030d28f5ce7d2e59df550e7fa19 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef _FADT_H_
 #define _FADT_H_
 
+#include <xen/hvm/ioreq.h>
+
 //
 // FADT Definitions, see ACPI 2.0 specification for details.
 //
@@ -51,7 +53,9 @@
 //
 // Fixed Feature Flags
 // 
-#define ACPI_FIXED_FEATURE_FLAGS (ACPI_PROC_C1|ACPI_SLP_BUTTON|ACPI_WBINVD|ACPI_PWR_BUTTON|ACPI_FIX_RTC)
+#define ACPI_FIXED_FEATURE_FLAGS (ACPI_PROC_C1 | ACPI_SLP_BUTTON | \
+                                  ACPI_WBINVD | ACPI_PWR_BUTTON | \
+                                  ACPI_FIX_RTC | ACPI_TMR_VAL_EXT)
 
 //
 // PM1A Event Register Block Generic Address Information
@@ -59,7 +63,6 @@
 #define ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID  ACPI_SYSTEM_IO
 #define ACPI_PM1A_EVT_BLK_BIT_WIDTH         0x20
 #define ACPI_PM1A_EVT_BLK_BIT_OFFSET        0x00
-#define ACPI_PM1A_EVT_BLK_ADDRESS           0x000000000000c010
 
 //
 // PM1B Event Register Block Generic Address Information
@@ -75,7 +78,6 @@
 #define ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID  ACPI_SYSTEM_IO
 #define ACPI_PM1A_CNT_BLK_BIT_WIDTH         0x10
 #define ACPI_PM1A_CNT_BLK_BIT_OFFSET        0x00
-#define ACPI_PM1A_CNT_BLK_ADDRESS           (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04)
 
 //
 // PM1B Control Register Block Generic Address Information
 #define ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID    ACPI_SYSTEM_IO
 #define ACPI_PM_TMR_BLK_BIT_WIDTH           0x20
 #define ACPI_PM_TMR_BLK_BIT_OFFSET          0x00
-#define ACPI_PM_TMR_BLK_ADDRESS             (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08)
 
 //
 // General Purpose Event 0 Register Block Generic Address
index 37623ff5ebba6a99b3e1a493180ca7b749357ff5..843a9232bfad19954f1700507fede3eeb6f6b36d 100644 (file)
@@ -5,6 +5,7 @@ obj-y += hvm.o
 obj-y += i8254.o
 obj-y += i8259.o
 obj-y += rtc.o
+obj-y += pmtimer.o
 obj-y += instrlen.o
 obj-y += intercept.o
 obj-y += io.o
index 47d7ca46c4ccc758f9bee9e2263731fa0679574e..f950d052957af919eba32eca03961a152a2baf55 100644 (file)
@@ -43,7 +43,7 @@
 #include <asm/mc146818rtc.h>
 #include <asm/spinlock.h>
 #include <asm/hvm/hvm.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/vpt.h>
 #include <asm/hvm/support.h>
 #include <public/sched.h>
 #include <public/hvm/ioreq.h>
@@ -285,6 +285,7 @@ void hvm_setup_platform(struct domain* d)
                pt_timer_fn, v, v->processor);
     pit_init(v, cpu_khz);
     rtc_init(v, RTC_PORT(0), RTC_IRQ);
+    pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS); 
 }
 
 void pic_irq_request(void *data, int level)
index 5f27ee25b2d8a6837ace094b1b4a825a8592519f..464ddee8f9615881d0d9b81f3e4b2a5180ca0ead 100644 (file)
@@ -38,7 +38,7 @@
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/io.h>
 #include <asm/hvm/support.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/vpt.h>
 #include <asm/current.h>
 
 /* Enable DEBUG_PIT may cause guest calibration inaccuracy */
index 8993572e106cd8256de23d153e4a92e0b816fd28..a1ce8ddf33cd9d4c3dfbb23d8f830e0dd34eb3a3 100644 (file)
@@ -35,7 +35,7 @@
 #include <asm/shadow.h>
 #include <asm/hvm/hvm.h>
 #include <asm/hvm/support.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/vpt.h>
 #include <asm/hvm/vpic.h>
 #include <asm/hvm/vlapic.h>
 
diff --git a/xen/arch/x86/hvm/pmtimer.c b/xen/arch/x86/hvm/pmtimer.c
new file mode 100644 (file)
index 0000000..e0c9353
--- /dev/null
@@ -0,0 +1,63 @@
+#include <asm/hvm/vpt.h>
+#include <asm/hvm/io.h>
+#include <asm/hvm/support.h>
+
+#define TMR_STS (1 << 0)
+static void pmt_update_status(void *opaque)
+{
+   PMTState *s = opaque;
+   s->pm1_status |= TMR_STS;
+
+   /* TODO: When TMR_EN == 1, generate a SCI event */
+
+   set_timer(&s->timer, NOW() + (1000000000ULL << 31) / FREQUENCE_PMTIMER);
+}
+
+static int handle_pmt_io(ioreq_t *p)
+{
+    struct vcpu *v = current;
+    PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
+    uint64_t curr_gtime;
+
+    if (p->size != 4 ||
+        p->pdata_valid ||
+        p->type != IOREQ_TYPE_PIO){
+        printk("HVM_PMT: wrong PM timer IO\n");
+        return 1;
+    }
+    
+    if (p->dir == 0) { /* write */
+        /* PM_TMR_BLK is read-only */
+        return 1;
+    } else if (p->dir == 1) { /* read */
+        curr_gtime = hvm_get_guest_time(s->vcpu);
+        s->pm1_timer += ((curr_gtime - s->last_gtime) * s->scale) >> 32;
+        p->u.data = s->pm1_timer;
+        s->last_gtime = curr_gtime;
+        return 1;
+    }
+    return 0;
+}
+
+void pmtimer_init(struct vcpu *v, int base)
+{
+    PMTState *s = &v->domain->arch.hvm_domain.pl_time.vpmt;
+
+    s->pm1_timer = 0;
+    s->pm1_status = 0;
+    s->scale = ((uint64_t)FREQUENCE_PMTIMER << 32) / ticks_per_sec(v);
+    s->vcpu = v;
+
+    init_timer(&s->timer, pmt_update_status, s, v->processor);
+    /* ACPI supports a 32-bit power management timer */
+    set_timer(&s->timer, NOW() + (1000000000ULL << 31) / FREQUENCE_PMTIMER);
+    
+    register_portio_handler(base, 4, handle_pmt_io);
+}
+
+void pmtimer_deinit(struct domain *d)
+{
+    PMTState *s = &d->arch.hvm_domain.pl_time.vpmt;
+
+    kill_timer(&s->timer);
+}
index 210168c26b8cf6481b806f291f566603241727ce..0f5e11986e0b64becc40d9fbbead94ba8e1e66eb 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include <asm/mc146818rtc.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/vpt.h>
 #include <asm/hvm/io.h>
 #include <asm/hvm/support.h>
 #include <asm/current.h>
index 92167d74fbab7b3a6184e8bee29c6b5c1618b38c..88c08024250e68def815a5635d9e3744e6e7c713 100644 (file)
@@ -922,6 +922,7 @@ static void svm_relinquish_guest_resources(struct domain *d)
 
     kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
     rtc_deinit(d);
+    pmtimer_deinit(d);
 
     if ( d->arch.hvm_domain.shared_page_va )
         unmap_domain_page_global(
@@ -937,6 +938,7 @@ static void svm_migrate_timers(struct vcpu *v)
     struct periodic_time *pt = 
         &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
     struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
+    struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
 
     if ( pt->enabled )
     {
@@ -947,6 +949,7 @@ static void svm_migrate_timers(struct vcpu *v)
         migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor);
     migrate_timer(&vrtc->second_timer, v->processor);
     migrate_timer(&vrtc->second_timer2, v->processor);
+    migrate_timer(&vpmt->timer, v->processor);
 }
 
 
index 476f8beae987a3aaf37cce78dc41ae6f4b87c1f7..ac1be73556fab38e77ea4f4b7f535da16366bcd4 100644 (file)
@@ -147,6 +147,7 @@ static void vmx_relinquish_guest_resources(struct domain *d)
 
     kill_timer(&d->arch.hvm_domain.pl_time.periodic_tm.timer);
     rtc_deinit(d);
+    pmtimer_deinit(d);
 
     if ( d->arch.hvm_domain.shared_page_va )
         unmap_domain_page_global(
@@ -489,6 +490,7 @@ void vmx_migrate_timers(struct vcpu *v)
 {
     struct periodic_time *pt = &(v->domain->arch.hvm_domain.pl_time.periodic_tm);
     struct RTCState *vrtc = &v->domain->arch.hvm_domain.pl_time.vrtc;
+    struct PMTState *vpmt = &v->domain->arch.hvm_domain.pl_time.vpmt;
 
     if ( pt->enabled )
     {
@@ -499,6 +501,7 @@ void vmx_migrate_timers(struct vcpu *v)
         migrate_timer(&VLAPIC(v)->vlapic_timer, v->processor);
     migrate_timer(&vrtc->second_timer, v->processor);
     migrate_timer(&vrtc->second_timer2, v->processor);
+    migrate_timer(&vpmt->timer, v->processor);
 }
 
 static void vmx_store_cpu_guest_regs(
index 6561519cb1c91c14792b6bab495d608375f38c66..0ebec779c18593e3bfe4cd7a3f81cf89c47ab41d 100644 (file)
@@ -23,7 +23,7 @@
 #define __ASM_X86_HVM_DOMAIN_H__
 
 #include <asm/hvm/vpic.h>
-#include <asm/hvm/vpit.h>
+#include <asm/hvm/vpt.h>
 #include <asm/hvm/vlapic.h>
 #include <asm/hvm/vioapic.h>
 #include <public/hvm/params.h>
diff --git a/xen/include/asm-x86/hvm/vpit.h b/xen/include/asm-x86/hvm/vpit.h
deleted file mode 100644 (file)
index 83b1af2..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * vpit.h: Virtual PIT definitions
- *
- * Copyright (c) 2004, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- * Place - Suite 330, Boston, MA 02111-1307 USA.
- */
-
-#ifndef __ASM_X86_HVM_VPIT_H__
-#define __ASM_X86_HVM_VPIT_H__
-
-#include <xen/config.h>
-#include <xen/init.h>
-#include <xen/lib.h>
-#include <xen/time.h>
-#include <xen/errno.h>
-#include <xen/time.h>
-#include <xen/timer.h>
-#include <asm/hvm/vpic.h>
-
-#define PIT_FREQ 1193181
-#define PIT_BASE 0x40
-
-typedef struct PITChannelState {
-    int count; /* can be 65536 */
-    u16 latched_count;
-    u8 count_latched;
-    u8 status_latched;
-    u8 status;
-    u8 read_state;
-    u8 write_state;
-    u8 write_latch;
-    u8 rw_mode;
-    u8 mode;
-    u8 bcd; /* not supported */
-    u8 gate; /* timer start */
-    s64 count_load_time;
-    /* irq handling */
-    struct vcpu      *vcpu;
-    struct periodic_time *pt;
-} PITChannelState;
-
-typedef struct PITState {
-    PITChannelState channels[3];
-    int speaker_data_on;
-    int dummy_refresh_clock;
-} PITState;
-
-#define RTC_SIZE 14
-typedef struct RTCState {
-    uint8_t cmos_data[RTC_SIZE];  /* Only handle time/interrupt part in HV */
-    uint8_t cmos_index;
-    struct tm current_tm;
-    int irq;
-    /* second update */
-    int64_t next_second_time;
-    struct timer second_timer;
-    struct timer second_timer2;
-    struct vcpu      *vcpu;
-    struct periodic_time *pt;
-} RTCState;
-   
-/*
- * Abstract layer of periodic time, one short time.
- */
-typedef void time_cb(struct vcpu *v, void *opaque);
-
-struct periodic_time {
-    char enabled;               /* enabled */
-    char one_shot;              /* one shot time */
-    char irq;
-    char first_injected;        /* flag to prevent shadow window */
-    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
-    u32 period;                 /* frequency in ns */
-    u64 period_cycles;          /* frequency in cpu cycles */
-    s_time_t scheduled;         /* scheduled timer interrupt */
-    u64 last_plt_gtime;         /* platform time when last IRQ is injected */
-    struct timer timer;         /* ac_timer */
-    time_cb *cb;
-    void *priv;                 /* ponit back to platform time source */
-};
-
-struct pl_time {    /* platform time */
-    struct periodic_time periodic_tm;
-    struct PITState      vpit;
-    struct RTCState      vrtc;
-    /* TODO: ACPI time */
-};
-
-static __inline__ s_time_t get_scheduled(
-    struct vcpu *v, int irq,
-    struct periodic_time *pt)
-{
-    if ( is_irq_enabled(v, irq) ) {
-        return pt->scheduled;
-    }
-    else
-        return -1;
-}
-
-extern u64 hvm_get_guest_time(struct vcpu *v);
-/*
- * get processor time.
- * unit: TSC
- */
-static __inline__ int64_t hvm_get_clock(struct vcpu *v)
-{
-    uint64_t  gtsc;
-
-    gtsc = hvm_get_guest_time(v);
-    return gtsc;
-}
-
-#define ticks_per_sec(v)      (v->domain->arch.hvm_domain.tsc_frequency)
-
-/* to hook the ioreq packet to get the PIT initialization info */
-extern void hvm_hooks_assist(struct vcpu *v);
-extern void pickup_deactive_ticks(struct periodic_time *vpit);
-extern struct periodic_time *create_periodic_time(u32 period, char irq, char one_shot, time_cb *cb, void *data);
-extern void destroy_periodic_time(struct periodic_time *pt);
-void pit_init(struct vcpu *v, unsigned long cpu_khz);
-void rtc_init(struct vcpu *v, int base, int irq);
-void rtc_deinit(struct domain *d);
-int is_rtc_periodic_irq(void *opaque);
-void pt_timer_fn(void *data);
-void pit_time_fired(struct vcpu *v, void *priv);
-
-#endif /* __ASM_X86_HVM_VPIT_H__ */
diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h
new file mode 100644 (file)
index 0000000..ada8936
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * vpt.h: Virtual Platform Timer definitions
+ *
+ * Copyright (c) 2004, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place - Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#ifndef __ASM_X86_HVM_VPT_H__
+#define __ASM_X86_HVM_VPT_H__
+
+#include <xen/config.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/time.h>
+#include <xen/errno.h>
+#include <xen/time.h>
+#include <xen/timer.h>
+#include <asm/hvm/vpic.h>
+
+#define PIT_FREQ 1193181
+#define PIT_BASE 0x40
+
+typedef struct PITChannelState {
+    int count; /* can be 65536 */
+    u16 latched_count;
+    u8 count_latched;
+    u8 status_latched;
+    u8 status;
+    u8 read_state;
+    u8 write_state;
+    u8 write_latch;
+    u8 rw_mode;
+    u8 mode;
+    u8 bcd; /* not supported */
+    u8 gate; /* timer start */
+    s64 count_load_time;
+    /* irq handling */
+    struct vcpu      *vcpu;
+    struct periodic_time *pt;
+} PITChannelState;
+
+typedef struct PITState {
+    PITChannelState channels[3];
+    int speaker_data_on;
+    int dummy_refresh_clock;
+} PITState;
+
+#define RTC_SIZE 14
+typedef struct RTCState {
+    uint8_t cmos_data[RTC_SIZE];  /* Only handle time/interrupt part in HV */
+    uint8_t cmos_index;
+    struct tm current_tm;
+    int irq;
+    /* second update */
+    int64_t next_second_time;
+    struct timer second_timer;
+    struct timer second_timer2;
+    struct vcpu      *vcpu;
+    struct periodic_time *pt;
+} RTCState;
+
+#define FREQUENCE_PMTIMER  3579545
+typedef struct PMTState {
+    uint32_t pm1_timer;
+    uint32_t pm1_status;
+    uint64_t last_gtime;
+    struct timer timer;
+    uint64_t scale;
+    struct vcpu *vcpu;
+} PMTState;
+
+/*
+ * Abstract layer of periodic time, one short time.
+ */
+typedef void time_cb(struct vcpu *v, void *opaque);
+
+struct periodic_time {
+    char enabled;               /* enabled */
+    char one_shot;              /* one shot time */
+    char irq;
+    char first_injected;        /* flag to prevent shadow window */
+    u32 pending_intr_nr;        /* the couner for pending timer interrupts */
+    u32 period;                 /* frequency in ns */
+    u64 period_cycles;          /* frequency in cpu cycles */
+    s_time_t scheduled;         /* scheduled timer interrupt */
+    u64 last_plt_gtime;         /* platform time when last IRQ is injected */
+    struct timer timer;         /* ac_timer */
+    time_cb *cb;
+    void *priv;                 /* ponit back to platform time source */
+};
+
+struct pl_time {    /* platform time */
+    struct periodic_time periodic_tm;
+    struct PITState      vpit;
+    struct RTCState      vrtc;
+    struct PMTState      vpmt;
+};
+
+static __inline__ s_time_t get_scheduled(
+    struct vcpu *v, int irq,
+    struct periodic_time *pt)
+{
+    if ( is_irq_enabled(v, irq) ) {
+        return pt->scheduled;
+    }
+    else
+        return -1;
+}
+
+extern u64 hvm_get_guest_time(struct vcpu *v);
+/*
+ * get processor time.
+ * unit: TSC
+ */
+static __inline__ int64_t hvm_get_clock(struct vcpu *v)
+{
+    uint64_t  gtsc;
+
+    gtsc = hvm_get_guest_time(v);
+    return gtsc;
+}
+
+#define ticks_per_sec(v)      (v->domain->arch.hvm_domain.tsc_frequency)
+
+/* to hook the ioreq packet to get the PIT initialization info */
+extern void hvm_hooks_assist(struct vcpu *v);
+extern void pickup_deactive_ticks(struct periodic_time *vpit);
+extern struct periodic_time *create_periodic_time(u32 period, char irq, char one_shot, time_cb *cb, void *data);
+extern void destroy_periodic_time(struct periodic_time *pt);
+void pit_init(struct vcpu *v, unsigned long cpu_khz);
+void rtc_init(struct vcpu *v, int base, int irq);
+void rtc_deinit(struct domain *d);
+void pmtimer_init(struct vcpu *v, int base);
+void pmtimer_deinit(struct domain *d);
+int is_rtc_periodic_irq(void *opaque);
+void pt_timer_fn(void *data);
+void pit_time_fired(struct vcpu *v, void *priv);
+
+#endif /* __ASM_X86_HVM_VPT_H__ */
index 8e92b004b1f787f95ac3a3d0575b6283bc6ffe50..992505e1c53b29c4574c467f860e6faa5e5be3cf 100644 (file)
@@ -86,6 +86,10 @@ struct buffered_iopage {
 };            /* sizeof this structure must be in one page */
 typedef struct buffered_iopage buffered_iopage_t;
 
+#define ACPI_PM1A_EVT_BLK_ADDRESS           0x000000000000c010
+#define ACPI_PM1A_CNT_BLK_ADDRESS           (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04)
+#define ACPI_PM_TMR_BLK_ADDRESS             (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08)
+
 #endif /* _IOREQ_H_ */
 
 /*